package com.navinfo.tripanalysis.common.arithmetic;

import com.navinfo.tripanalysis.common.arithmetic.common.*;
import com.navinfo.tripanalysis.common.arithmetic.common.VarRange;
import com.navinfo.tripanalysis.common.arithmetic.common.VarCommon;
import com.navinfo.tripanalysis.common.arithmetic.manager.AbstractArithmetic;
import com.navinfo.tripanalysis.common.arithmetic.manager.IArithmetic;
import com.navinfo.tripanalysis.common.config.ConfigMap;

import java.util.*;

/**
 * 海拔区间统计算法<br/>
 * 海拔分段：(-∞,-500),[-500,0), [0,500),[500,1000),[1000,1500) .....[5000,5500),[5500,+∞)用一维数组按升序存放对应的区间统计信息<br/>
 * 在算法实现时，因为大部份的区间无数据，所以用Map实现稀疏数组（key为数组下标，value为统计值）<br/>
 * 依赖{@link Mileage}计算的里程、油耗差<br/>
 * 输出：统计<br/>
 * @author 沈东生
 */
public class RangeAltitude extends AbstractArithmetic<VarRange> {
    /**
     * 每个区间段长度(单位：米 ),大于0有效
     */
    int rangeStep = ConfigMap.getInteger("AltitudeRange_Step");
    /**
     * 海拔区间段下限(单位：米 ),小于0有效
     */
    int minThreshold = ConfigMap.getInteger("AltitudeRange_Min_Threshold");
    /**
     * 海拔区间段上限(单位：米 ),大于0有效
     */
    int maxThreshold = ConfigMap.getInteger("AltitudeRange_Max_Threshold");

    /**
     * 负区间段最小索引值（负数）（-2,-1）
     */
    private int minIdx;
    /**
     * 正区间段最大索引值（正数）（0,1）
     */
    private int maxIdx;
    /**
     * 负区间段个数
     */
    private int negativeRangeSize;
    /**
     * 正区间段个数
     */
    private int positiveRangeSize;
    /**
     * 整个区间段个数
     */
    int allRangeSize;
    /**
     * 区间段下限数组
     */
    private Integer[] lowerLimits;
    /**
     * 区间段上限数组
     */
    private Integer[] upperLimits;

    /**
     * 是否初始化
     */
    private boolean init = false;

    @Override
    public IArithmetic init(DrivingData drivingData) {
        IArithmetic rtn = super.init(drivingData);
        if(!init){
            initConfig();
        }
        return rtn;
    }

    @Override
    public void calculate() {
        logger.debug("进入[海拔区间统计算法].");

        if (allRangeSize <= 0) {
            logger.debug("退出[海拔区间统计算法]，阀值参数错误！");
            return;
        }

        CommonData commonData = getCommonData();
        int height = commonData.getHeight();
        int dffTime = commonData.getDffTime();
        double dffOil = commonData.getDffFuel();
        double dffDistance = commonData.getDffMileage();

        int idx;
        if (height < 0) {
            idx = height<minThreshold ? minIdx : (int) Math.floor(1.0 * height / rangeStep);
        } else {
            idx = height>maxThreshold ? maxIdx : (int) Math.floor(1.0 * height / rangeStep);
        }

        //存储的索引（从0开始）
        int storeIdx = idx + negativeRangeSize;

        //累加指定区间段的统计指标
        VarCommon rangeData = getObj().getRangeData(storeIdx);
        rangeData.addMileage(dffDistance);
        rangeData.addFuel(dffOil);
        rangeData.addDuration(dffTime);

        logger.debug("退出[海拔区间统计算法],storeIdx={}.", storeIdx);
    }

    @Override
    public void collect(OuterStatisticData statisticDataOut) {
        Map<Integer, InterRangeData> toRanges = getObj().convertRanges();

        //设置区间段统计内部对象的上下限
        for(Map.Entry<Integer, InterRangeData> entry : toRanges.entrySet()){
            Integer key = entry.getKey();
            InterRangeData value = entry.getValue();
            value.setLowerLimit(lowerLimits[key]);
            value.setUpperLimit(upperLimits[key]);
        }

        statisticDataOut.setAltitudeRanges(toRanges);
    }


    private void initConfig() {
        if (rangeStep <= 0) {
            throw new RuntimeException("AltitudeRange_Step应大于0");
        }
        if (minThreshold >= 0) {
            throw new RuntimeException("AltitudeRange_Min_Threshold应小于0");
        }
        if (maxThreshold <= 0) {
            throw new RuntimeException("AltitudeRange_Max_Threshold应大于0");
        }
        if (minThreshold % rangeStep != 0) {
            throw new RuntimeException(String.format("minThreshold:%d应是rangeStep:%d的整数倍", minThreshold, rangeStep));
        }
        if (maxThreshold % rangeStep != 0) {
            throw new RuntimeException(String.format("maxThreshold:%d应是rangeStep:%d的整数倍", maxThreshold, rangeStep));
        }

        minIdx = minThreshold / rangeStep -1;
        maxIdx = maxThreshold / rangeStep;
        logger.debug("[海拔区间统计算法]minIdx:" + minIdx);
        logger.debug("[海拔区间统计算法]maxIdx:" + maxIdx);

        negativeRangeSize = Math.abs(minIdx);
        positiveRangeSize = maxIdx;
        allRangeSize = negativeRangeSize + positiveRangeSize + 1;
        logger.debug("[海拔区间统计算法]negativeRangeSize:" + negativeRangeSize);
        logger.debug("[海拔区间统计算法]positiveRangeSize:" + positiveRangeSize);
        logger.debug("[海拔区间统计算法]allRangeSize:" + allRangeSize);

        //区间的下限值赋值，lowerLimits[0]为null代表负无穷
        lowerLimits = new Integer[allRangeSize];
        for (int i=1; i<allRangeSize; i++) {
            lowerLimits[i] = minThreshold + rangeStep*(i-1);
        }
        logger.debug("[海拔区间统计算法]lowerLimits:" + Arrays.toString(lowerLimits));

        //区间的上限值赋值，upperLimits[size-1]为null代表正无穷
        upperLimits = new Integer[allRangeSize];
        for (int i=0; i<allRangeSize-1; i++) {
            upperLimits[i] = minThreshold + rangeStep*i;
        }

        init = true;
        logger.debug("[海拔区间统计算法]upperLimits:" + Arrays.toString(upperLimits));
    }
}
